# -*- coding: utf-8 -*-
"""
-------------------------------------------------
  File Name：   controller_main
  Description :
  Author :    崔术森
  Eamil  :    deer_cui@163.com
  date：     2021/8/12
-------------------------------------------------
  Change Activity:
          2021/8/12:
-------------------------------------------------
"""
__author__ = '崔术森'

import os
import threading
import time

from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import QTextCursor, QRegExpValidator, QColor, QPixmap
from PyQt5.QtWidgets import *
from pyqtUi.ComUi import Ui_MainWindow
from comToolUtils.Utils import *
import serial
import serial.tools.list_ports


class controller_main(QMainWindow, Ui_MainWindow):
    """
    Class documentation goes here.
    """
    # 刷新显示/接收数据
    freshTxt_show = pyqtSignal(str)
    # 发数据
    sendDataSig = pyqtSignal()

    textSend = pyqtSignal(str)

    def __init__(self, parent=None):
        """
        Constructor

        @param parent reference to the parent widget
        @type QWidget
        """
        super(controller_main, self).__init__(parent)
        self.setupUi(self)
        self.util = Utils()
        # 串口
        self.com = serial.Serial()
        # 事件
        self.freshTxt_show.connect(self.updateReceivedDataDisplay)
        self.sendDataSig.connect(self.sendData)
        self.textSend.connect(self.upTxtSend)
        # 定时发送数据
        self.forSendTimer = QTimer(self)
        self.forSendTimer.timeout.connect(self.sendData)
        self.isForSending = False
        # 输入框按键按压事件
        self.txt_send.connect_customized_slot(self.inputKeyPress)
        self.isREC = False
        self.last_time = 0
        # 保存到文件的历史 文件存储路径
        self.oldLogFilePath = ""
        # 是否保存文件
        self.isSaveLog = False
        # 写入文件模式
        self.writeLogType = "w"
        self.filePoint = None
        self.isFirstWrite = True
        # 循环批量发送
        self.batForSend = False
        # 历史按钮点击的发送
        self.isTableBtnClick = False

        self.batTimer = QTimer(self)
        self.batTimer.timeout.connect(self.batDoWork)
        self.batData = ""
        self.batDelay = ""
        self.batCount = 0
        # 接收区自动换行
        self.recAutoChangeLine = self.checkBox_auto_changeline.isChecked()

    @pyqtSlot(int)
    def on_comboBox_baud_activated(self, p):
        """
        波特率下拉框点击自定义输入
        :param p:
        :return:
        """
        if self.comboBox_baud.currentText() == "自己输":
            self.comboBox_baud.setEditable(True)
            self.comboBox_baud.clearEditText()
            reg = QRegExp('[0-9]+$')
            validator = QRegExpValidator(self)
            validator.setRegExp(reg)
            self.comboBox_baud.setValidator(validator)
            self.comboBox_baud.setStyleSheet("""
            """)
        else:
            self.comboBox_baud.setEditable(False)

    @pyqtSlot()
    def on_pushButton_open_close_seri_clicked(self):
        """
        打开串口按钮点击
        :return:
        """
        self.openCloseSerial()

    @pyqtSlot(bool)
    def on_radioButton_send_ascii_toggled(self, checked):
        """
        发送地方的HEX或者ASCII radio Button按钮点击事件
        :param checked:
        :return:
        """
        if self.radioButton_send_ascii.isChecked():
            self.onSendSettingsAsciiClicked()
        else:
            self.onSendSettingsHexClicked()

    @pyqtSlot(bool)
    def on_radioButton_input_ascii_toggled(self, checked):
        """
        接收地方的HEX或者ASCII radio Button按钮点击事件
        :param checked:
        :return:
        """
        pass

    def onSendSettingsHexClicked(self):
        """
        发送区域HEX radio点击事件被执行方法
        :return:
        """
        try:
            data = self.txt_send.toPlainText()
            if data == "":
                return
            data = self.util.asciiB2HexString(data.encode())
            self.txt_send.clear()
            self.txt_send.insertPlainText(data)
        except Exception as e:
            print(e)
            self.tips.emit(str(e))

    def onSendSettingsAsciiClicked(self):
        """
        发送区域ASCII radio点击事件被执行方法
        :return:
        """
        try:
            data = self.txt_send.toPlainText()
            self.txt_send.clear()
            if data != "":
                data = self.util.hexStringB2Hex(data).decode("utf-8", 'ignore')
                self.txt_send.insertPlainText(data)
        except Exception as e:
            print("format error")
            self.tips.emit(str(e))

    @pyqtSlot()
    def on_btn_send_clicked(self):
        """
        发送按钮点击
        :return:
        """
        # 循环发送
        if self.checkBox_for.isChecked() and not self.isForSending:
            # if int(self.spinBox_for_time.value()) == 0:
            #     self.spinBox_for_time.setFocus()
            #     self.util.doShakeWindow(self.spinBox_for_time)
            #     return
            print("循环发送")
            # 只有循环发送的时候才禁用控件
            # self.sendStateChange(False)
            self.sendDataSig.emit()
        # 停止循环发送
        elif self.isForSending:
            print("停止循环发送")
            self.isForSending = False
            self.forSendTimer.stop()
            self.sendStateChange(True)
        else:
            # print("普通发送")
            self.sendDataSig.emit()

    @pyqtSlot()
    def on_pushButton_clear_input_clicked(self):
        """"""
        # 清空输入框
        self.clearSendShow()

    @pyqtSlot()
    def on_pushButton_clear_output_clicked(self):
        """
        清空接收框
        :return:
        """
        self.clearTxtShow()

    def openCloseSerial(self):
        """
        打开串口处理
        :return:
        """
        try:
            if self.com.is_open:
                self.isREC = False
                self.closeSerialDo()
                print(self.com)
            else:
                try:
                    # 串口
                    com_num = self.comboBox_seri_num.currentText().split(" ")[0]
                    # 波特率
                    baud = self.comboBox_baud.currentText()
                    # 校验位
                    check_bit = self.comboBox_check_bit.currentText()
                    # 数据位
                    data_bit = self.comboBox_data_bit.currentText()
                    # 停止位
                    stop_bit = self.comboBox_stop_bit.currentText()
                    # 流控制
                    contro_stream = self.comboBox_control_stream.currentText()

                    self.com.baudrate = int(baud)
                    self.com.port = com_num
                    if not self.com.port:
                        raise Exception("请选择串口")
                    self.com.bytesize = int(data_bit)
                    self.com.parity = check_bit[0]
                    self.com.stopbits = float(stop_bit)
                    self.com.timeout = None
                    if contro_stream != "NONE":
                        print(contro_stream)
                        if contro_stream == "XON/XOFF":
                            self.com.xonxoff = True
                        elif contro_stream == "RTS/CTS":
                            self.com.rtscts = True
                        elif contro_stream == "DSR/DTR":
                            self.com.dsrdtr = True
                        elif contro_stream == "DSR/DTR/XON/XOFF":
                            self.com.xonxoff = self.com.dsrdtr = True
                        else:
                            self.com.xonxoff = self.com.rtscts = True
                    self.com.open()
                    self.pushButton_open_close_seri.setIcon(self.getIcon("open"))
                    # self.pushButton_open_close_seri.setText("关闭")
                    print("open success")
                    print(self.com)
                    self.comStatusChange(False)
                    # self.setDisableSettingsSignal.emit(True)
                    self.isREC = True
                    self.receiveProcess = threading.Thread(target=self.data_receive)
                    self.receiveProcess.setDaemon(True)
                    self.receiveProcess.start()
                    # self.timer.start(1)
                except Exception as e:
                    self.closeSerialDo()
                    self.tips.emit(str(e))
                    # self.setDisableSettingsSignal.emit(False)
        except Exception as e:
            self.tips.emit(str(e))
            return

    def closeSerialDo(self):
        """
        关闭串口操作
        :return:
        """
        self.com.xonxoff = self.com.rtscts = self.com.dsrdtr = False
        self.isREC = False
        # self.timer.stop()
        if self.filePoint is not None and not self.checkBox_save_log_toFIle.isChecked():
            self.filePoint.close()
        self.forSendTimer.stop()
        self.sendStateChange(True)
        # self.btn_send.setText("发送")
        # self.pushButton_open_close_seri.setText("打开")
        self.com.close()
        self.comStatusChange(True)
        self.pushButton_open_close_seri.setIcon(self.getIcon("close"))
        self.batForSend = False
        print("串口关闭成功")

    def comStatusChange(self, bool_value):
        """
        启用/禁用串口下拉框
        :return:
        """
        self.comboBox_seri_num.setEnabled(bool_value)
        self.comboBox_baud.setEnabled(bool_value)
        self.comboBox_check_bit.setEnabled(bool_value)
        self.comboBox_data_bit.setEnabled(bool_value)
        self.comboBox_stop_bit.setEnabled(bool_value)
        self.comboBox_control_stream.setEnabled(bool_value)
        if bool_value:
            self.pushButton_open_close_seri.setText("打开")
        else:
            self.pushButton_open_close_seri.setText("关闭")

    def sendStateChange(self, bool_value):
        """
        循环发送设置状态设置
        :param bool_value:
        :return:
        """
        self.radioButton_send_hex.setEnabled(bool_value)
        self.radioButton_send_ascii.setEnabled(bool_value)
        self.checkBox_auto_parse_rtn.setEnabled(bool_value)
        self.checkBox_at_auto_n.setEnabled(bool_value)
        self.checkBox_auto_send_checkbit.setEnabled(bool_value)
        self.checkBox_open_target_file.setEnabled(bool_value)
        self.checkBox_for.setEnabled(bool_value)
        self.spinBox_for_time.setEnabled(bool_value)
        self.txt_send.setEnabled(bool_value)
        if bool_value:
            self.isForSending = False
            self.btn_send.setText("发送")
        else:
            self.btn_send.setText("停止发送")

    def sendMsg_showTitle(self, msg):
        # ▶◀
        titleContent = "[{0}]# SEND {1}>".format(self.util.getNowDate(), self.radioButton_send_ascii.text())
        styleTitle = '<span style=\" color: {0};\">{1}</span>'.format(self.cfg.sendTitleColor, titleContent)
        self.txt_show.append(styleTitle)
        strMsg = '<span style=\" color: {0};\">{1}</span>'.format(self.cfg.sendContentColor, msg)
        # print(strMsg)
        self.txt_show.append(strMsg)
        self.txt_show.insertPlainText("\n")
        if self.isFirstWrite:
            self.saveLogToFile(titleContent + "\n")
        else:
            self.saveLogToFile("\n" + titleContent + "\n")
        self.saveLogToFile(msg + "\n")
        # 008000

    def recMsg_showTitle(self):
        titleContent = "[{0}]# RECV {1}>".format(self.util.getNowDate(), self.radioButton_input_ascii.text())
        styleTitle = '<span style=\" color: {0};\">{1}</span>'.format(self.cfg.sendTitleColor, titleContent)
        self.txt_show.append(styleTitle)
        self.txt_show.append("")
        # self.txt_show.setStyleSheet("""
        #             color:#008000
        #             """)
        self.saveLogToFile(titleContent + "\n")

    def getSendData(self):
        """
        获取输入框的信息
        :return:
        """
        data = self.txt_send.toPlainText()
        if data == "":
            return
        # print("获取的是:",data,type(data))
        if self.radioButton_send_hex.isChecked():
            data = self.util.hexStringB2Hex(data)
        else:
            data = data.encode()
        # print("返回的是:", data,type(data))
        return data

    def sendData(self):
        """
        发送数据
        :return:
        """
        try:
            if self.com.is_open:
                if self.txt_send.toPlainText() == "" or self.txt_send.toPlainText() == b'':
                    self.txt_send.setFocus()
                    self.util.doShakeWindow(self.txt_send)
                    return
                # self.sendMsg_showTitle(self.txt_send.toPlainText())
                data = self.getSendData()
                if not self.isTableBtnClick:
                    self.addToHistory()
                self.isTableBtnClick = False
                if self.checkBox_at_auto_n.isChecked():
                    data = data.decode() + "\r\n"
                    data = data.encode()

                if self.radioButton_send_hex.isChecked():
                    # print(data,data.decode(),type(data.decode()))
                    # print(self.util.asciiB2HexString(data))
                    self.sendMsg_showTitle(self.util.asciiB2HexString(data))
                else:
                    self.sendMsg_showTitle(self.txt_send.toPlainText())
                # if data == -1:
                #     return
                # print(self.sendArea.toPlainText())
                # print("实际写入的是:",data,type(data))
                # self.sendCount += len(data)
                # print("write Data is :", data)
                self.com.write(data)
                if self.recAutoChangeLine:
                    self.txt_show.moveCursor(QTextCursor.End)
                # 循环发送
                if self.checkBox_for.isChecked() and not self.isForSending:
                    self.forSendTimer.start(self.spinBox_for_time.value())
                    # print(self.isForSending)
                    self.isForSending = True
                    # 只有循环发送的时候才禁用控件
                    self.sendStateChange(False)
                    # print(self.spinBox_for_time.value())
            else:
                self.tips.emit(str("串口未打开"))
                self.closeSerialDo()
                return
        except Exception as e:
            self.tips.emit(str(e))
            self.closeSerialDo()
            return

    def data_receive(self):
        print("数据接收进程开启...")
        while self.isREC:
            try:
                # num = self.com.inWaiting()
                num = max(1, min(2048, self.com.in_waiting))
            except Exception as e:
                # self.timer.stop()
                self.com.close()
                print(e)
                return None
            if num > 1:
                data = self.com.read(num)
                # num = len(data)
                if data != b'':
                    # print("data:{0}selfdata:{1}".format(data,self.data))

                    if self.radioButton_input_hex.isChecked():
                        strReceived = self.util.asciiB2HexString(data)
                        self.freshTxt_show.emit(strReceived)
                    else:
                        # print("data:",data)
                        self.freshTxt_show.emit(data.decode("utf-8", "ignore").replace("\n", ""))

                # 统计接收字符的数量

    def updateReceivedDataDisplay(self, str):
        """
        数据显示到接收框中
        :param str:要显示的数据
        :return:
        """
        if str != "":
            if time.time() - self.last_time > self.cfg.REC_TITLE_TIMEOUT:
                self.recMsg_showTitle()
                # self.txt_show.insertPlainText("\n")
            # 接收字体为绿色
            self.txt_show.setTextColor(QColor.fromRgb(self.cfg.recColor_R, self.cfg.recColor_G, self.cfg.recColor_B))
            self.txt_show.insertPlainText(str)
            if self.recAutoChangeLine:
                self.txt_show.moveCursor(QTextCursor.End)
            self.last_time = time.time()
            self.saveLogToFile(str)

    def inputKeyPress(self):
        """
        输入框回车事件
        :return:
        """
        # 发送按钮按压事件
        # self.sendData()
        self.on_btn_send_clicked()

    @pyqtSlot()
    def on_checkBox_save_log_toFIle_clicked(self):
        """
        保存log到文件按钮点击
        :return:
        """
        print(self.checkBox_save_log_toFIle.isChecked())
        if self.checkBox_save_log_toFIle.isChecked():
            # 弹出文件保存框
            if self.oldLogFilePath == "":
                self.oldLogFilePath = os.getcwd()
            print(self.oldLogFilePath)
            fileName_choose, filetype = QFileDialog.getOpenFileName(self, "保存日志到文件", self.oldLogFilePath,
                                                                    "所有文件 (*);;日志文件(*.log);;文本文件(*.txt)")
            if fileName_choose == "":
                """
                没选文件
                """
                self.checkBox_save_log_toFIle.setCheckState(False)
                return
            else:
                """
                选了文件
                """
                # print(os.path.getsize(fileName_choose))
                if os.path.getsize(fileName_choose) > 0:
                    rep = QMessageBox.warning(None, "提示", "目标文件不为空,请选择保存日志文件方式!",
                                              QMessageBox.Abort | QMessageBox.Retry | QMessageBox.Ignore,
                                              QMessageBox.Retry)
                    # retry = 覆盖,ignore = 追加,其他为取消
                    if rep == QMessageBox.Retry:
                        print("覆盖")
                        self.writeLogType = "w"
                        self.isSaveLog = True
                    elif rep == QMessageBox.Ignore:
                        print("追加")
                        self.writeLogType = "a"
                        self.isSaveLog = True
                    else:
                        print("取消")
                        self.checkBox_save_log_toFIle.setCheckState(False)
                else:
                    self.writeLogType = "w"
                    self.isSaveLog = True

                if self.isSaveLog:
                    self.oldLogFilePath = fileName_choose
                    self.isFirstWrite = True
                    self.filePoint = open(self.oldLogFilePath, encoding="utf-8", mode=self.writeLogType)
            print(fileName_choose, self.isSaveLog, self.writeLogType, self.filePoint)
        else:
            self.isSaveLog = False
            self.isFirstWrite = False
            if self.filePoint is not None:
                self.filePoint.close()
                self.filePoint = None

    def saveLogToFile(self, str):
        """
        日志写入log文件
        :param str:
        :return:
        """
        if self.isSaveLog and self.filePoint is not None:
            if self.isFirstWrite:
                self.isFirstWrite = False
            try:
                self.filePoint.write(str)
                self.filePoint.flush()
                # print("写入log...")
            except Exception as e:
                self.filePoint.close()
                print(e)

    def addToHistory(self):
        """
        历史数据
        :return:
        """
        send_txt = self.txt_send.toPlainText()
        if send_txt == "" or send_txt is None:
            return
        timeStr = ""
        btn = QPushButton()
        lb = QLabel()
        try:
            for i in range(self.tableWidget_right_log_histroy_send.rowCount()):
                historyTxt = self.tableWidget_right_log_histroy_send.cellWidget(i, 0).text()
                if send_txt == historyTxt:
                    self.tableWidget_right_log_histroy_send.removeRow(i)
                    break
            timeStr = time.strftime("%H:%M:%S %m-%d", time.localtime())
            btn.setText(timeStr)
            btn.clicked.connect(self.tableBtnClick)
            lb.setText(send_txt)

            self.tableWidget_right_log_histroy_send.setRowCount(
                self.tableWidget_right_log_histroy_send.rowCount() + 1)
            self.tableWidget_right_log_histroy_send.setCellWidget(
                self.tableWidget_right_log_histroy_send.rowCount() - 1, 0,
                lb)
            self.tableWidget_right_log_histroy_send.setCellWidget(
                self.tableWidget_right_log_histroy_send.rowCount() - 1, 1,
                btn)
            self.tableWidget_right_log_histroy_send.scrollToBottom()
        except Exception as e:
            print(e)

    def tableBtnClick(self):
        """
        表格按钮点击
        :return:
        """
        if self.isForSending or self.batForSend:
            return
        button = self.sender()
        if button:

            if self.isForSending:
                return
            if self.checkBox_for.isChecked():
                self.checkBox_for.setCheckState(False)

            # 确定位置的时候这里是关键
            row = self.tableWidget_right_log_histroy_send.indexAt(button.pos()).row()
            column = self.tableWidget_right_log_histroy_send.indexAt(button.pos()).column()
            # print(row,column)
            # print(self.tableWidget_right_log_histroy_send.cellWidget(row,column-1).text())
            getText = self.tableWidget_right_log_histroy_send.cellWidget(row, column - 1).text()
            self.txt_send.setText(getText)
            self.isTableBtnClick = True
            self.on_btn_send_clicked()

    @pyqtSlot()
    def on_action1_triggered(self):
        """
        换主题
        :return:
        """
        if self.skin == 0:
            # 换成黑色
            self.skin = 1
            self.cfg.sendTitleColor = "#f8f8f2"
            # 发送内容颜色
            self.cfg.sendContentColor = "#98afff"
            # 接收颜色
            self.cfg.recColor_R = 79
            self.cfg.recColor_G = 249
            self.cfg.recColor_B = 110
            with open("./stylesheets/darkstyle.qss", "r", encoding="utf-8") as f:
                self.setStyleSheet(f.read())
            with open("./stylesheets/darkstyle.qss", "r", encoding="utf-8") as f:
                self.addBatDia.setStyleSheet(f.read())
        else:
            # 换成白色
            self.skin = 0
            self.cfg.sendTitleColor = "#6d6d6d"
            self.cfg.sendContentColor = "#0000ff"
            self.cfg.recColor_R = 0
            self.cfg.recColor_G = 128
            self.cfg.recColor_B = 0
            with open("./stylesheets/lightstyle.qss", "r", encoding="utf-8") as f:
                self.setStyleSheet(f.read())
            with open("./stylesheets/lightstyle.qss", "r", encoding="utf-8") as f:
                self.addBatDia.setStyleSheet(f.read())

    @pyqtSlot()
    def on_action2_triggered(self):
        """
        menu菜单子菜单关闭点击
        :return:
        """
        self.close()

    @pyqtSlot()
    def on_pushButton_send_log_add_clicked(self):
        self.addBatDia.isSave = False
        self.addBatDia.exec()
        # 保存
        if self.addBatDia.isSave:
            # print("save")
            ascOrhex = "ASCII" if self.addBatDia.ascChecked else "HEX"
            # print(ascOrhex)
            delay = self.addBatDia.spinBox_edit_delay.value()
            # print(delay,type(delay))
            mark = self.addBatDia.lineEdit_edit_mark.text()
            # print(mark)
            content = self.addBatDia.txt_editData_input.toPlainText()
            # print(content)
            self.tabWidget_right_bat.setRowCount(self.tabWidget_right_bat.rowCount() + 1)

            checkbox = QCheckBox()
            checkbox.setChecked(True)
            self.tabWidget_right_bat.setCellWidget(self.tabWidget_right_bat.rowCount() - 1, 0, checkbox)
            lb = QLabel(str(delay))
            self.tabWidget_right_bat.setCellWidget(self.tabWidget_right_bat.rowCount() - 1, 1, lb)
            content_show = QLabel(content)
            self.tabWidget_right_bat.setCellWidget(self.tabWidget_right_bat.rowCount() - 1, 2, content_show)
            btn = QPushButton(mark)
            btn.clicked.connect(self.batBtnClick)
            self.tabWidget_right_bat.setCellWidget(self.tabWidget_right_bat.rowCount() - 1, 3, btn)
            self.tabWidget_right_bat.scrollToBottom()

    def batBtnClick(self):
        """
        批量发送界面，表格里面的按钮点击
        :return:
        """
        if self.isForSending or self.batForSend:
            return
        btn = self.sender()
        if btn:
            # print(self.tabWidget_right_bat.currentRow(), self.tabWidget_right_bat.currentColumn())
            if self.isForSending:
                return
            if self.checkBox_for.isChecked():
                self.checkBox_for.setCheckState(False)

            # 确定位置的时候这里是关键
            row = self.tabWidget_right_bat.currentRow()
            column = self.tabWidget_right_bat.currentColumn()
            # print(row,column)
            # print(self.tableWidget_right_log_histroy_send.cellWidget(row,column-1).text())
            getText = self.tabWidget_right_bat.cellWidget(row, column - 1).text()
            self.txt_send.setText(getText)
            self.on_btn_send_clicked()

    @pyqtSlot()
    def on_pushButton_send_log_delete_clicked(self):
        """
        批量发送，删除按钮点击
        :return:
        """
        removeList = []
        for i in range(self.tabWidget_right_bat.rowCount()):
            if self.tabWidget_right_bat.cellWidget(i, 0).isChecked():
                # 如果选中删除此行
                removeList.append(i)
        print(len(removeList))
        if len(removeList) == 0:
            self.showBox("未选中行!")
            return
        else:
            if self.showConfirm("删除提示", "你确定要删除{0}行数据吗?".format(len(removeList)), "q"):
                for j in removeList[::-1]:
                    self.tabWidget_right_bat.removeRow(j)

    @pyqtSlot()
    def on_pushButton_send_log_up_clicked(self):
        """
        批量发送，向上移动
        :return:
        """
        count = 0
        currentIndex = -1
        for i in range(self.tabWidget_right_bat.rowCount()):
            if self.tabWidget_right_bat.cellWidget(i, 0).isChecked():
                count += 1
                currentIndex = i
                if count > 1:
                    self.showBox("一次只能移动一行,请选择一行!")
                    return
        if currentIndex != -1:
            upIndex = currentIndex - 1
            if currentIndex == 0:
                # 第一行和最后一行交换
                upIndex = self.tabWidget_right_bat.rowCount() - 1
            # print(currentIndex)
            # 获取当前行的所有格,两行交换
            upCellList = []
            currentCellList = []
            for i in range(self.tabWidget_right_bat.columnCount()):
                # 获取两行元素暂存起来
                currentCellList.append(self.copy_widget(self.tabWidget_right_bat.cellWidget(currentIndex, i)))
                upCellList.append(self.copy_widget(self.tabWidget_right_bat.cellWidget(upIndex, i)))
            # 清空两行
            for len in range(self.tabWidget_right_bat.columnCount()):
                self.tabWidget_right_bat.setCellWidget(currentIndex, len, None)
                self.tabWidget_right_bat.setCellWidget(upIndex, len, None)
            # 交换两行元素
            for index, cell in enumerate(currentCellList):
                self.tabWidget_right_bat.setCellWidget(upIndex, index, cell)

            for index_down, cell_down in enumerate(upCellList):
                self.tabWidget_right_bat.setCellWidget(currentIndex, index_down, cell_down)

    @pyqtSlot()
    def on_pushButton_send_log_down_clicked(self):
        """
        批量按钮，向下按钮
        :return:
        """
        count = 0
        currentIndex = -1
        for i in range(self.tabWidget_right_bat.rowCount()):
            if self.tabWidget_right_bat.cellWidget(i, 0).isChecked():
                count += 1
                currentIndex = i
                if count > 1:
                    self.showBox("一次只能移动一行,请选择一行!")
                    return
        if currentIndex != -1:
            downIndex = currentIndex + 1
            if currentIndex == self.tabWidget_right_bat.rowCount() - 1:
                # 最后一行和首行交换
                downIndex = 0
            print(currentIndex)
            # 获取当前行的所有格,两行交换
            downCellList = []
            currentCellList = []
            for i in range(self.tabWidget_right_bat.columnCount()):
                # 获取两行元素暂存起来
                currentCellList.append(self.copy_widget(self.tabWidget_right_bat.cellWidget(currentIndex, i)))
                downCellList.append(self.copy_widget(self.tabWidget_right_bat.cellWidget(downIndex, i)))
            # 清空两行,不能直接删除
            for l in range(self.tabWidget_right_bat.columnCount()):
                self.tabWidget_right_bat.setCellWidget(currentIndex, l, None)
                self.tabWidget_right_bat.setCellWidget(downIndex, l, None)

            # 交换两行元素
            for index, cell in enumerate(currentCellList):
                self.tabWidget_right_bat.setCellWidget(downIndex, index, cell)

            for index_down, cell_down in enumerate(downCellList):
                self.tabWidget_right_bat.setCellWidget(currentIndex, index_down, cell_down)

    def copy_widget(self, w):
        """
        表格子元素复制
        :param w:
        :return:
        """
        if isinstance(w, QtWidgets.QWidget):
            # new_w = type(w)()
            # print(new_w)
            if isinstance(w, QtWidgets.QCheckBox):
                c = QCheckBox()
                if w.isChecked():
                    c.setChecked(True)
                return c
            if isinstance(w, QtWidgets.QLabel):
                l = QLabel()
                if w.text() != "":
                    l.setText(w.text())
                return l
            if isinstance(w, QtWidgets.QPushButton):
                b = QPushButton()
                b.clicked.connect(self.batBtnClick)
                if w.text() != "":
                    b.setText(w.text())
                return b

    @pyqtSlot(bool)
    def on_checkBox_send_log_for_send_toggled(self, checked):
        """
        批量发送界面,发送复选框
        :param checked:
        :return:
        """
        if checked:
            if self.tabWidget_right_bat.rowCount() == 0:
                return
            if self.isForSending:
                self.showBox("正在循环发送,请停止后再试!")
                self.checkBox_send_log_for_send.setCheckState(False)
                return
            if self.checkBox_for.isChecked():
                self.checkBox_for.setCheckState(False)
            # 遍历选中的行
            send_data = []
            send_delay = []
            for row in range(self.tabWidget_right_bat.rowCount()):
                if self.tabWidget_right_bat.cellWidget(row, 0).isChecked():
                    send_delay.append(self.tabWidget_right_bat.cellWidget(row, 1).text())
                    send_data.append(self.tabWidget_right_bat.cellWidget(row, 2).text())
            if len(send_data) == 0 or len(send_delay) == 0:
                return
            self.batForSend = True if self.checkBox_send_log_for.isChecked() else False
            self.btn_send.setVisible(False)
            self.sendStateChange(False)
            self.batCount = 0
            self.batData = send_data
            self.batDelay = send_delay
            self.batTimer.start(int(send_delay[0]))
        else:
            self.batForSend = False

    @pyqtSlot(bool)
    def on_checkBox_send_log_for_toggled(self, checked):
        if checked:
            self.batForSend = checked
        else:
            self.batForSend = False

    def upTxtSend(self, s):
        """
        发送内容更新
        :param s:
        :return:
        """
        self.txt_send.setText(s)

    def batDoWork(self):
        if not self.com.is_open:
            self.tips.emit("串口未打开!")
            self.checkBox_send_log_for_send.setCheckState(False)
            if self.batTimer.isActive():
                self.batTimer.stop()
            return
        try:
            self.textSend.emit(self.batData[self.batCount])
            self.on_btn_send_clicked()
            self.batTimer.stop()
            self.batCount += 1
            if self.batCount == len(self.batData) and self.batForSend:
                self.batCount = 0
            if self.batCount == len(self.batData):
                # 一遍发完
                self.checkBox_send_log_for_send.setCheckState(False)
                self.btn_send.setVisible(True)
                self.sendStateChange(True)
                return
            else:
                self.batTimer.start(int(self.batDelay[self.batCount]))
        except Exception as e:
            print(e)
            self.batForSend = False
            self.checkBox_send_log_for_send.setCheckState(False)
            self.btn_send.setVisible(True)
            self.sendStateChange(True)

    @pyqtSlot(bool)
    def on_checkBox_auto_changeline_toggled(self,checked):
        if checked:
            self.recAutoChangeLine = True
        else:
            self.recAutoChangeLine = False
        print(self.recAutoChangeLine)
